package cn.buk.tms.dao;

import cn.buk.tms.entity.base.BaseOrderInfo_;
import cn.buk.tms.entity.order.flight.FlightRefundOrder_;
import cn.buk.tms.factory.OperationLogFactory;
import cn.buk.tms.sc.SearchFlightOrderCriteria;
import cn.buk.common.util.DateUtil;
import cn.buk.tms.entity.misc.OperationLog;
import cn.buk.tms.entity.order.OrderAttachment;
import cn.buk.tms.entity.misc.PaymentMethod;
import cn.buk.tms.entity.misc.Supplier;
import cn.buk.tms.entity.order.flight.FlightRefundOrder;
import jakarta.persistence.criteria.*;
import org.springframework.stereotype.Repository;

import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static cn.buk.tms.common.constant.TmsOrderConstant.*;

/**
 * @author yfdai
 */
@Repository
@Transactional
public class FlightRefundOrderDaoImpl extends AbstractDao implements FlightRefundOrderDao {


    private OperationLog createFlightRefundOrderLog(int enterpriseId, String username, int refundOrderId, String remark) {
        OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
        log.setEnterpriseId(enterpriseId);
        log.setOperator(username);
        log.setOrderId(refundOrderId);
        log.setContent(remark);

        return log;
    }

    @Override
    public int createFlightRefundOrder(FlightRefundOrder info) {
        int retCode;


        em.persist(info);

        retCode = info.getId();
        if (retCode > 0) {
            OperationLog log = createFlightRefundOrderLog(info.getEnterpriseId(), info.getOperator(), retCode, "创建退票单");
            em.persist(log);
        }


        return retCode;
    }


    @Override
    public int processFlightRefund(int enterpriseId, String username, int orderId) {
        int retCode = em.createQuery("update FlightRefundOrder o set " +
                        "o.status = :newStatus, " +
                        "o.ticketer = :ticketer, " +
                        "o.lastUpdate = :lastUpdate " +
                        "where " +
                        "o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus ")
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("id", orderId)
                .setParameter("ticketer", username)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("oldStatus", FlightRefundOrder.ORDER_STATUS_WAITING)
                .setParameter("newStatus", FlightRefundOrder.ORDER_STATUS_WORKING)
                .executeUpdate();

        if (retCode == 1) {
            var log = OperationLogFactory.createFlightRefundOrderOperationLog();
            log.setEnterpriseId(enterpriseId);
            log.setOrderId(orderId);
            log.setOperator(username);
            log.setContent("我来处理");

            em.persist(log);
        } else {
            logger.error("processFlightRefund({}, {}, {}): {}", enterpriseId, username, orderId, retCode);
        }

        return retCode;
    }

    @Override
    public int cancelFlightRefund(int enterpriseId, String username, int id) {
        int retCode = em.createQuery("update FlightRefundOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate where " +
                        "o.id = :id and o.enterpriseId = :enterpriseId and o.status in (:oldStatus1, :oldStatus2, :oldStatus3) ")
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("id", id)
                .setParameter("oldStatus1", FlightRefundOrder.ORDER_STATUS_WAITING)
                .setParameter("oldStatus2", FlightRefundOrder.ORDER_STATUS_WORKING)
                .setParameter("oldStatus3", FlightRefundOrder.ORDER_STATUS_SUBMITTED)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("newStatus", FlightRefundOrder.ORDER_STATUS_CANCELED)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
            log.setEnterpriseId(enterpriseId);
            log.setOrderId(id);
            log.setOperator(username);
            log.setContent("取消退票单");

            em.persist(log);


        } else {
            throw new RuntimeException("rollback");
        }


        return retCode;
    }

    @Override
    public int reopenFlightRefund(int enterpriseId, String username, int id) {
        int retCode =  em.createQuery("update FlightRefundOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate where " +
                        "o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus")
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("id", id)
                .setParameter("oldStatus", FlightRefundOrder.ORDER_STATUS_CANCELED)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("newStatus", FlightRefundOrder.ORDER_STATUS_WAITING)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
            log.setEnterpriseId(enterpriseId);
            log.setOrderId(id);
            log.setOperator(username);
            log.setContent("重新打开退票单");

            em.persist(log);


        } else {
            throw new RuntimeException("rollback");
        }


        return retCode;
    }

    /**
     * 提交退票
     */
    @Override
    public int submitFlightRefund(int enterpriseId, String username, int refundTicketId) {
        int retCode = em.createQuery("update FlightRefundOrder o set o.status = :newStatus, " +
                        "o.submitDate = :submitDate, " +
                        "o.lastUpdate = :lastUpdate " +
                        "where " +
                        "o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus ")
                .setParameter("newStatus", FlightRefundOrder.ORDER_STATUS_SUBMITTED)
                .setParameter("submitDate", DateUtil.getCurDate())
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("id", refundTicketId)
                .setParameter("oldStatus", FlightRefundOrder.ORDER_STATUS_WORKING)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
            log.setEnterpriseId(enterpriseId);
            log.setOrderId(refundTicketId);
            log.setOperator(username);
            log.setContent("已提交退票");

            em.persist(log);


        } else {
            throw new RuntimeException("rollback");
        }


        return retCode;
    }

    @Override
    public int setFlightRefundAirlineRefundedAmount(int enterpriseId, String username, int id, double amount) {
        int retCode = em.createQuery("update FlightRefundOrder o " +
                        "set o.airlineRefundAmount = :amount, o.lastUpdate = :lastUpdate " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("amount", amount)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode != 1) {
            throw new RuntimeException("rollback");
        }

        OperationLog log = createFlightRefundOrderLog(enterpriseId, username, id, "航司预退金额：" + amount);
        em.persist(log);

        return retCode;
    }

    @Override
    public int setFlightRefundAirlineRefundedStatus(int enterpriseId, String username, int id) {
        int retCode;


        FlightRefundOrder order = em.find(FlightRefundOrder.class, id);
        em.refresh(order);
        if (order.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("EnterpriseId is not equal.");
        }

        order.setLastUpdate(DateUtil.getCurDateTime());

        OperationLog log = createFlightRefundOrderLog(enterpriseId, username, id, "退票单状态：航司预退.");
        em.persist(log);

        if (order.getStatus() == FlightRefundOrder.ORDER_STATUS_SUBMITTED) {
            retCode = FlightRefundOrder.ORDER_STATUS_AIR_REFUNDED;
            order.setStatus(FlightRefundOrder.ORDER_STATUS_AIR_REFUNDED);
        } else if (order.getStatus() == FlightRefundOrder.ORDER_STATUS_PASSENGER_REFUNDED) {
            retCode = FlightRefundOrder.ORDER_STATUS_DONE;
            order.setStatus(FlightRefundOrder.ORDER_STATUS_DONE);

            log = createFlightRefundOrderLog(enterpriseId, username, id, "退票单状态：完成退票.");
            em.persist(log);
        } else {
            throw new RuntimeException("Status is not allowed.");
        }

        em.merge(order);

        return retCode;
    }


    /**
     * @param enterpriseId 企业id
     * @param username     用户名
     * @param id           退票单id
     * @param amount       金额
     * @return 成功则返回最新的退票单状态，失败则返回 <=0
     */
    @Override
    public int setFlightRefundPassengerRefundedAmount(int enterpriseId, String username, int id, double amount) {
        int retCode =  em.createQuery("update FlightRefundOrder o " +
                        "set o.passengerRefundAmount = :amount, o.lastUpdate = :lastUpdate " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("amount", amount)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = createFlightRefundOrderLog(enterpriseId, username, id, "实退客户金额：" + amount);
            em.persist(log);


        } else {
            throw new RuntimeException("rollback");
        }


        return retCode;
    }

    @Override
    public int setFlightRefundPassengerRefundedStatus(int enterpriseId, String username, int id) {
        int retCode;


        FlightRefundOrder order = em.find(FlightRefundOrder.class, id);
        em.refresh(order);
        if (order.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("EnterpriseId is not equal.");
        }

        order.setLastUpdate(DateUtil.getCurDateTime());
        order.setPsgRefundDate(DateUtil.getCurDate());

        OperationLog log = createFlightRefundOrderLog(enterpriseId, username, id, "退票单状态：已退客户.");
        em.persist(log);

        if (order.getStatus() == FlightRefundOrder.ORDER_STATUS_SUBMITTED) {
            order.setStatus(FlightRefundOrder.ORDER_STATUS_PASSENGER_REFUNDED);
            retCode = FlightRefundOrder.ORDER_STATUS_PASSENGER_REFUNDED;
        } else if (order.getStatus() == FlightRefundOrder.ORDER_STATUS_AIR_REFUNDED) {
            order.setStatus(FlightRefundOrder.ORDER_STATUS_DONE);
            retCode = FlightRefundOrder.ORDER_STATUS_DONE;

            log = createFlightRefundOrderLog(enterpriseId, username, id, "退票单状态: 完成退票");
            em.persist(log);
        } else {
            throw new RuntimeException("Status is not allowed.");
        }

        em.merge(order);


        return retCode;
    }

    private List<Predicate> buildPredicates_searchFlightRefundOrder(CriteriaBuilder cb, Root<FlightRefundOrder> root,
                                                                    int enterpriseId, SearchFlightOrderCriteria sc, List<Integer> allowedCustomerIds) {
        List<Predicate> predicates = new ArrayList<>();

        Predicate predicate = cb.conjunction();
        predicates.add(predicate);

        predicate = cb.equal(root.get(BaseOrderInfo_.enterpriseId), enterpriseId);
        predicates.add(predicate);

        if (sc.getCustomerId() == 0) {
            // 散客
            predicate = cb.equal(root.get(BaseOrderInfo_.customerType), 0);
            predicates.add(predicate);
        } else if (sc.getCustomerId() > 0) {
            // 企业
            predicate = cb.equal(root.get(BaseOrderInfo_.customer), sc.getCustomerId());
            predicates.add(predicate);
        }

        if (sc.getBalCode() != null && sc.getTicketNo() != null) {
            if (sc.getBalCode().length() == 3 && sc.getTicketNo().length() == 10) {
                predicate = cb.equal(root.get(FlightRefundOrder_.balanceCode), sc.getBalCode());
                predicates.add(predicate);

                predicate = cb.equal(root.get(FlightRefundOrder_.ticketNo), sc.getTicketNo());
                predicates.add(predicate);
            }
        }

        if (sc.getIntlTicket() > -1) {
            predicate = cb.equal(root.get(FlightRefundOrder_.intlTicket), sc.getIntlTicket());
            predicates.add(predicate);
        }

        if (sc.getName() != null && sc.getName().trim().length() > 0) {
            predicate = cb.like(root.get(FlightRefundOrder_.psgName), "%" + sc.getName().trim() + "%");
            predicates.add(predicate);
        }

        if (sc.getStatus() > -1) {
            predicate = cb.equal(root.get(FlightRefundOrder_.status), sc.getStatus());
            predicates.add(predicate);
        }

        if (sc.getPnrNo() != null && sc.getPnrNo().trim().length() > 0) {
            predicate = cb.equal(root.get(FlightRefundOrder_.pnrNo), sc.getPnrNo().trim());
            predicates.add(predicate);
        }

        if (sc.getTicketNo().length() > 0) {
            String temp = sc.getTicketNo().trim();
            if (temp.length() > 10) {
                temp = temp.substring(temp.length() - 10);
            }
            if (temp.length() < 10) {
                predicate = cb.like(root.get(FlightRefundOrder_.ticketNo), "%" + temp + "%");
            } else {
                // length = 10
                predicate = cb.equal(root.get(FlightRefundOrder_.ticketNo), temp);
            }
            predicates.add(predicate);
        }

        if (sc.getBeginDate() != null) {
            predicate = cb.greaterThanOrEqualTo(root.get(BaseOrderInfo_.createTime), sc.getBeginDate());
            predicates.add(predicate);
        }

        if (sc.getEndDate() != null) {
            predicate = cb.lessThanOrEqualTo(root.get(BaseOrderInfo_.createTime), DateUtil.addDays(sc.getEndDate(), 1));
            predicates.add(predicate);
        }

        if (sc.getIdno() != null && sc.getIdno().trim().length() > 0) {
            predicate = cb.like(root.get(FlightRefundOrder_.idNo), "%" + sc.getIdno().trim() + "%");
            predicates.add(predicate);
        }

        if (sc.getName() != null && sc.getName().trim().length() > 0) {
            predicate = cb.like(root.get(FlightRefundOrder_.psgName), "%" + sc.getName().trim() + "%");
            predicates.add(predicate);
        }

        if (sc.getOrderNo().length() > 0) {
            predicate = cb.equal(root.get(FlightRefundOrder_.orderNo), sc.getOrderNo());
            predicates.add(predicate);
        }

        if (sc.getRefundOrderNo().length() > 0) {
            predicate = cb.equal(root.get(FlightRefundOrder_.refundOrderNo), sc.getRefundOrderNo());
            predicates.add(predicate);
        }

        if (sc.getAirRefundStatus() == 0) {
            predicate = cb.isNull(root.get(FlightRefundOrder_.airRefundStatus));
            predicate = cb.or(predicate, cb.equal(root.get(FlightRefundOrder_.airRefundStatus), 0));
            predicates.add(predicate);
        } else if (sc.getAirRefundStatus() == 1) {
            predicate = cb.equal(root.get(FlightRefundOrder_.airRefundStatus), 1);
            predicates.add(predicate);
        }

        if (sc.getOp1() != null && sc.getOp1().trim().length() > 0) {
            predicate = cb.equal(root.get(BaseOrderInfo_.operator), sc.getOp1());
            predicates.add(predicate);
        }

        if (allowedCustomerIds != null && !allowedCustomerIds.isEmpty()) {
            // 只允许查看指定的企业客户的订单
            predicate = cb.in(root.get(BaseOrderInfo_.customer).get("id")).value(allowedCustomerIds);
            predicates.add(predicate);
        }

        return predicates;
    }

    @Override
    public List<FlightRefundOrder> searchFlightRefundOrder(int enterpriseId, SearchFlightOrderCriteria sc, List<Integer> allowedCustomerIds) {
        List<FlightRefundOrder> results = null;

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<FlightRefundOrder> cq = cb.createQuery(FlightRefundOrder.class);
        Root<FlightRefundOrder> root = cq.from(FlightRefundOrder.class);
        root.alias("o");

        var predicates0 = buildPredicates_searchFlightRefundOrder(cb, root, enterpriseId, sc, allowedCustomerIds);


        //计算根据条件查询得出的数据总数
        CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
        Root<FlightRefundOrder> countRoot = countQuery.from(FlightRefundOrder.class);
        countRoot.alias("o");

        var predicates1 = buildPredicates_searchFlightRefundOrder(cb, countRoot, enterpriseId, sc, allowedCustomerIds);

        countQuery.select(cb.count(countRoot)).where(predicates1.toArray(new Predicate[0]));
        Long count = em.createQuery(countQuery).getSingleResult();

        int maxResults = count.intValue();
        if (maxResults > 0) {
            cq.where(predicates0.toArray(new Predicate[0]));
            List<Order> orderByes = new ArrayList<>();
            orderByes.add(cb.desc(root.get("id")));

            cq.orderBy(orderByes);

            sc.getPage().setRowCount(maxResults);
            results = em.createQuery(cq)
                    .setFirstResult(sc.getPage().getFirstPosition())
                    .setMaxResults(sc.getPage().getPageSize()).getResultList();
        }


        if (results == null) {
            results = new ArrayList<>();
        }

        return results;

    }

    @Override
    public FlightRefundOrder getFlightRefundOrderDetail(int id) {
        return em.find(FlightRefundOrder.class, id);
    }

    @Override
    public FlightRefundOrder getFlightRefundOrderDetailByRefundOrderNo(int enterpriseId, String refundOrderNo) {

        List<FlightRefundOrder> list = em.createQuery("select o from FlightRefundOrder o where o.enterpriseId = :enterpriseId " +
                        "and o.refundOrderNo = :refundOrderNo", FlightRefundOrder.class)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("refundOrderNo", refundOrderNo)
                .getResultList();
        return !list.isEmpty() ? list.get(0) : null;

    }

    @Override
    public List<OperationLog> searchFlightRefundOrderHistory(int enterpriseId, int id) {

        return em.createQuery("select o from OperationLog o where o.enterpriseId = :enterpriseId " +
                        "and o.objectType = :objectType and o.orderId = :orderId order by o.id desc", OperationLog.class)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("objectType", OPERATING_OBJECT_FLIGHT_REFUND_ORDER)
                .setParameter("orderId", id)
                .getResultList();

    }

    /**
     * 根据退票订单生成退票报表
     */
    @Override
    public List<FlightRefundOrder> searchFlightRefundByOrder(final int enterpriseId, final Date beginDate, final Date endDate, final int supplierId) {


        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<FlightRefundOrder> cq = cb.createQuery(FlightRefundOrder.class);
        Root<FlightRefundOrder> root = cq.from(FlightRefundOrder.class);
        root.alias("o");

        List<Predicate> predicates = new ArrayList<>();

        Predicate where = cb.conjunction();
        predicates.add(where);

        where = cb.equal(root.get(BaseOrderInfo_.enterpriseId), enterpriseId);
        predicates.add(where);

        where = cb.notEqual(root.get(FlightRefundOrder_.status), FlightRefundOrder.ORDER_STATUS_CANCELED);
        predicates.add(where);

        where = cb.greaterThan(root.get(BaseOrderInfo_.createTime), beginDate);
        predicates.add(where);

        final Date endDate0 = DateUtil.addDays(endDate, 1);
        where = cb.lessThan(root.get(BaseOrderInfo_.createTime), endDate0);
        predicates.add(where);

        if (supplierId > 0) {
            where = cb.equal(root.get(BaseOrderInfo_.supplier), supplierId);
            predicates.add(where);
        }

        cq.where(predicates.toArray(new Predicate[0]));
        List<Order> orderByes = new ArrayList<>();
        orderByes.add(cb.asc(root.get("id")));

        cq.orderBy(orderByes);

        List<FlightRefundOrder> results = em.createQuery(cq).getResultList();


        if (results == null) {
            results = new ArrayList<>();
        }

        return results;
    }

    @Override
    public int updateRefundOrderPrice(int enterpriseId, String username, int id, double airRefundCharge, double serviceCharge) {
        int retCode = em.createQuery("update FlightRefundOrder o " +
                        "set o.airRefundCharge = :airRefundCharge, o.serviceCharge = :serviceCharge, o.lastUpdate = :lastUpdate " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId and (o.status = :status1 or o.status = :status2)")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("status1", FlightRefundOrder.ORDER_STATUS_WORKING)
                .setParameter("status2", FlightRefundOrder.ORDER_STATUS_WAITING)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("airRefundCharge", airRefundCharge)
                .setParameter("serviceCharge", serviceCharge)
                .executeUpdate();

        if (retCode == 1) {
            String remark = "修改：航司退票费 " + airRefundCharge + ", 服务费 " + serviceCharge;
            OperationLog log = createFlightRefundOrderLog(enterpriseId, username, id, remark);
            em.persist(log);


        } else {
            throw new RuntimeException("rollback");
        }


        return retCode;
    }

    @Override
    public int updateRefundOrderRemark(int enterpriseId, String username, int id, String remark) {
        int retCode =  em.createQuery("update FlightRefundOrder o " +
                        "set o.remark = :remark, o.lastUpdate = :lastUpdate " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("remark", remark)
                .executeUpdate();

        if (retCode == 1) {
            String remark1 = "修改备注为：" + remark;
            OperationLog log = createFlightRefundOrderLog(enterpriseId, username, id, remark1);
            em.persist(log);


        } else {
            throw new RuntimeException("rollback");
        }


        return retCode;
    }

    @Override
    public List<FlightRefundOrder> searchUnpaidOrders(int max) {
        return em.createQuery("select o from FlightRefundOrder o " +
                        "where o.status = :status " +
                        "and o.createTime >= :createTime " +
                        "and (o.payStatus is null or o.payStatus <> 2)  order by o.id desc", FlightRefundOrder.class)
                .setParameter("status", FlightRefundOrder.ORDER_STATUS_DONE)
                .setParameter("createTime", getMinBeginDate())
                .setMaxResults(max)
                .getResultList();
    }

    @Override
    public void setOrderWrittenOff(int enterpriseId, String username, int id, String remark) {
        int retCode = em.createQuery("update FlightRefundOrder o set " +
                        "o.payStatus = 2 " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId and (o.payStatus is null or o.payStatus <> 2)")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = createFlightRefundOrderLog(enterpriseId, username, id, "已销账：" + remark);

            em.persist(log);
        }


    }

    // 航司实退了，金额和状态
    @Override
    public int setFinallyAirRefunded(int enterpriseId, String username, int id, double amount) {
        int retCode = em.createQuery("update FlightRefundOrder o " +
                        "set o.airlineRefundAmountFinal = :amount, o.lastUpdate = :lastUpdate, o.airRefundStatus = :airStatus " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("amount", amount)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("airStatus", 1)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = createFlightRefundOrderLog(enterpriseId, username, id, "航司实退金额：" + amount);
            em.persist(log);


        } else {
            throw new RuntimeException("rollback");
        }


        return retCode;
    }

    @Override
    public int rollbackRefundOrderStatus(final int enterpriseId, final String username, final int orderId, final String remark0) {

        FlightRefundOrder o = em.find(FlightRefundOrder.class, orderId);
        if (o == null || o.getEnterpriseId() != enterpriseId) {
            throw new RuntimeException("FlightRefundOrder is not existed.");
        }

        if (o.getStatus() != FlightRefundOrder.ORDER_STATUS_DONE) {
            throw new RuntimeException("Cannot rollback order status.");
        }


        // 已完成 -> 已提交
       int  retCode = em.createQuery("update FlightRefundOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("oldStatus", FlightRefundOrder.ORDER_STATUS_DONE)
                .setParameter("newStatus", FlightRefundOrder.ORDER_STATUS_SUBMITTED)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();


        String remark = "状态回滚已提交: " + remark0;
        OperationLog log = createFlightRefundOrderLog(enterpriseId, username, orderId, remark);

        em.persist(log);

        return retCode;
    }

    @Override
    public List<FlightRefundOrder> searchByFlightOrderNo(int enterpriseId, String orderNo) {
        return em.createQuery("select o from FlightRefundOrder o where o.enterpriseId = :enterpriseId and o.orderNo = :orderNo", FlightRefundOrder.class)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("orderNo", orderNo)
                .getResultList();
    }

    @Override
    public int updateRefundOrderTicketNo(int enterpriseId, String username, int orderId,
                                         String balCode, String tickNo) {
        int retCode = em.createQuery("update FlightRefundOrder o set " +
                        "o.balanceCode = :balanceCode, o.ticketNo = :ticketNo " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("balanceCode", balCode)
                .setParameter("ticketNo", tickNo)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
            log.setEnterpriseId(enterpriseId);
            log.setOrderId(orderId);
            log.setOperator(username);
            log.setContent("退票的票号修改为：" + balCode + "-" + tickNo);

            em.persist(log);
        }

        return retCode;
    }

    @Override
    public List<FlightRefundOrder> searchMobileIsNull(int enterpriseId) {
        final Date startDate = DateUtil.getYesterday();
        return em.createQuery("select o from FlightRefundOrder o "
                        + "where o.enterpriseId = :enterpriseId " +
                        "and o.mobile is null " +
                        "and o.createTime >= :createDate "
                        + "order by o.id", FlightRefundOrder.class)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("createDate", startDate)
                .getResultList();
    }

    @Override
    public List<FlightRefundOrder> searchSupplierIsNull(int enterpriseId) {
        final Date startDate = DateUtil.addDays(DateUtil.getYesterday(), -90);
        return em.createQuery("select o from FlightRefundOrder o "
                        + "where o.enterpriseId = :enterpriseId " +
                        "and o.supplier is null " +
                        "and o.createTime >= :createDate "
                        + "order by o.id desc", FlightRefundOrder.class)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("createDate", startDate)
                .setMaxResults(50)
                .getResultList();
    }

    @Override
    public void updateRefundOrderMobile(int enterpriseId, String username, int id, String mobile) {
        int retCode = em.createQuery("update FlightRefundOrder o set " +
                        "o.mobile = :mobile " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("mobile", mobile)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
            log.setEnterpriseId(enterpriseId);
            log.setOrderId(id);
            log.setOperator(username);
            log.setContent("乘机人电话：" + mobile);

            em.persist(log);
        }

    }

    @Override
    public int updateRefundOrderSupplier(int enterpriseId, String username, int id, Supplier supplier, PaymentMethod pm) {
        int retCode = em.createQuery("update FlightRefundOrder o set " +
                        "o.supplier = :supplier, o.paymentMethod = :pm " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId and o.supplier is null and o.paymentMethod is null ")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("supplier", supplier)
                .setParameter("pm", pm)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
            log.setEnterpriseId(enterpriseId);
            log.setOrderId(id);
            log.setOperator(username);
            log.setContent("修改供应商为 " + supplier.getName() + ", 支出方式为 " + pm.getName());

            em.persist(log);
        }

        return retCode;
    }

    @Override
    public List<FlightRefundOrder> searchRefundOrdersNeedRefreshDetr(int enterpriseId, int max) {
        final Date startDate = DateUtil.addDays(DateUtil.getCurDate(), -365);

        return em.createQuery("select o from FlightRefundOrder o "
                        + "where o.enterpriseId = :enterpriseId " +
                        "and o.status = :status " +
                        "and (o.detrRefreshStatus is null or o.detrRefreshStatus = 0) " +
                        "and o.createTime >= :createDate " +
                        "order by o.id desc", FlightRefundOrder.class)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("status", FlightRefundOrder.ORDER_STATUS_DONE)
                .setParameter("createDate", startDate)
                .setMaxResults(max)
                .getResultList();
    }

    @Override
    public void updateRefundOrderDetrStatus(int enterpriseId, String username, final int orderId, int status) {

        int retCode = em.createQuery("update FlightRefundOrder o " +
                        "set " +
                        "o.detrRefreshStatus = :status, o.detrRefreshTime = :refreshTime " +
                        "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("status", status)
                .setParameter("refreshTime", DateUtil.getCurDateTime())
                .executeUpdate();
        if (retCode != 1) {
            throw new RuntimeException("updateRefundOrderDetrStatus failed.");
        }

        FlightRefundOrder orderInfo = em.find(FlightRefundOrder.class, orderId);
        em.createQuery("update FlightOrder o set o.detrRefreshStatus = :status " +
                        "where o.enterpriseId = :enterpriseId and o.orderNo = :orderNo")
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("orderNo", orderInfo.getOrderNo())
                .setParameter("status", 1)
                .executeUpdate();

        OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
        log.setEnterpriseId(enterpriseId);
        log.setOrderId(orderId);
        log.setOperator(username);
        log.setContent("更新detr信息(" + status + ").");

        em.persist(log);

    }

  @Override
  public int updateExternalOrderNo(int enterpriseId, String username, int orderId, String externalOrderNo, String remark) {
      int retCode = em.createQuery("update FlightRefundOrder o set " +
                      "o.externalOrderNo = :orderNo, o.lastUpdate = :lastUpdate " +
                      "where o.id = :id and o.enterpriseId = :enterpriseId")
              .setParameter("id", orderId)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("orderNo", externalOrderNo)
              .setParameter("lastUpdate", DateUtil.getCurDateTime())
              .executeUpdate();
      if (retCode == 1) {
          appendRefundOrderLog(enterpriseId, username, orderId, remark);
      }

      return retCode;
  }

  @Override
  public List<FlightRefundOrder> searchWaiting(int enterpriseId, Date startDate) {
      return em.createQuery("select o from FlightRefundOrder o "
                      + "where o.enterpriseId = :enterpriseId " +
                      "and (o.status = :status0 or o.status = :status1 or o.status = :status2) " +
                      "and o.createTime >= :createDate " +
                      "order by o.id desc", FlightRefundOrder.class)
              .setParameter("enterpriseId", enterpriseId)
              .setParameter("status0", FlightRefundOrder.ORDER_STATUS_WAITING)
              .setParameter("status1", FlightRefundOrder.ORDER_STATUS_WORKING)
              .setParameter("status2", FlightRefundOrder.ORDER_STATUS_SUBMITTED)
              .setParameter("createDate", startDate)
              .getResultList();
  }

  @Override
    public int appendRefundOrderLog(int enterpriseId, String username, int orderId, String remark) {
        OperationLog log = OperationLogFactory.createFlightRefundOrderOperationLog();
        log.setEnterpriseId(enterpriseId);
        log.setOrderId(orderId);
        log.setOperator(username);
        log.setContent(remark);

        em.persist(log);

        return log.getId();
    }

    @Override
    public int saveRefundOrderAttachment(int enterpriseId, String username, int orderId, List<OrderAttachment> attachments) {
        return saveOrderAttachment(enterpriseId, username, ORDER_TYPE_FLIGHT_REFUND, orderId, attachments);
    }

    @Override
    public List<OrderAttachment> searchAttachments(int enterpriseId, int orderId) {
        return searchAttachments(enterpriseId, ORDER_TYPE_FLIGHT_REFUND, orderId);
    }
}
